package server;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;

/**
 * The monitor for the shared data in the camera
 */
public class Monitor {
	
	private int command;
	private String openDocument;
	private boolean killed;
	private String receivedCommandData;
	private HashMap<String,Document> documentArchive;
	private String loggedInPeer;
	private String loggedInWard;
	private boolean isDoctor;
	private boolean isGov;
	private File auditFile;
	private BufferedWriter auditFileWriter;
	
	/**
	 * The monitor for the shared data in the camera
	 */
	public Monitor(){
		command = Server.IDLE_COMMAND;
		killed = false;
		receivedCommandData = "";
		openDocument = "";
		documentArchive = new HashMap<String,Document>();
		loggedInPeer = "";
		loggedInWard = "";
		isDoctor = false;
		isGov = false;
		auditFile = new File("logfile");
		int n = 0;
		while(auditFile.exists()){
			auditFile = new File("logfile" + String.valueOf(n++));
		}
		try {
			auditFile.createNewFile();
			auditFileWriter = new BufferedWriter(new FileWriter(auditFile));
		} catch (IOException e) {
			e.printStackTrace();
		}
populateWithDocs();
	}
	
	/**
	 * Stores and processes the latest command received
	 * @param newCommand received command
	 * @param commandData data for the command
	 */
	public synchronized void setCommand(int newCommand, String commandData){
		audit("Received command: " + String.valueOf(newCommand) + " " + commandData);
		command = newCommand;
		receivedCommandData = commandData;
		switch(command){
		case 2: //Open (and fetch) document
			if (documentArchive.containsKey(commandData)){
				if (documentArchive.get(commandData).hasReadAccess(loggedInPeer, loggedInWard)){
					openDocument = commandData;
				} else {
					command = 102;
					receivedCommandData = "Access Denied for document: " + receivedCommandData;
				}
			} else {
				command = 102;
				receivedCommandData = "Unknown document: " + receivedCommandData;
			}
			break;
		case 4: //Add to document 
			String[] doc = commandData.split(":::");
			if (openDocument.equals(doc[0])){
				command = 104;
				receivedCommandData = "document not open: " + receivedCommandData;
			} else if (documentArchive.get(commandData).hasWriteAccess(loggedInPeer)){
				documentArchive.get(doc[0]).addNotes(doc[1]);
			} else {
				command = 104;
				receivedCommandData = "Access Denied for document: " + receivedCommandData;
			}
			
			break;
		case 5: //Close document
			openDocument = "";
			break;
		case 6: //Create document
			if (isDoctor){
				String[] doc2 = commandData.split(":::");
				documentArchive.put(doc2[0], new Document(doc2[1], doc2[2], doc2[3], doc2[4]));
			} else {
				command = 106;
				receivedCommandData = "Access Denied: Not a doctor";
			}
			break; 
		case 7: //Remove document
			if (documentArchive.containsKey(commandData)){
				if (isGov){
					documentArchive.remove(commandData);
				} else {
					command = 107;
					receivedCommandData = "Access Denied: Not an Agency";
				}
			} else {
				command = 107;
				receivedCommandData = "Unknown document: " + receivedCommandData;
			}
			break; 
		default:
			break;
		}
		notifyAll();
	}

	/**
	 * Kills the {@link server.ReadCommands command} handler thread.
	 */
	public synchronized void killThreads(){
		killed = true;
		loggedInPeer = "";
		loggedInWard = "";
		isDoctor = false;
		isGov = false;
	}

	/**
	 * @return if the threads should die. The {@link server.ReadCommands command} handler threads check this.
	 */
	public synchronized boolean threadKilled() {
		return killed;
	}

	/**
	 * Retrieves the next message to send to the client.
	 * @return String with the message, sans the command.
	 */
	public synchronized String getDoc() {
		while (command == Server.IDLE_COMMAND){
			try {
				wait();
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		String ans = "";
		switch(command){
		case 1: //Fetch document list
			for (String s: documentArchive.keySet()){
				ans += "Dokument: " + s + "\n";
			}
			receivedCommandData = "";
			break;
		case 2: //Open (and fetch) document
			//done in setReceivedCommand()
		case 3: //Fetch document
			ans = documentArchive.get(openDocument).toString();
			receivedCommandData = "";
			break;
		case 4: //Add to document 
			//done in setReceivedCommand()
		case 5: //Close document
			//done in setReceivedCommand()
		case 6: //Create document
			//done in setReceivedCommand()
		case 7: //Delete document
			//done in setReceivedCommand()
		case Server.IDLE_COMMAND: //Idle mode
			ans = "EOF";
			receivedCommandData = "";
			break;
		case 101:
		case 102:
		case 103:
		case 104:
		case 105:
		case 106:
		case 107:
			ans = receivedCommandData;
			receivedCommandData = "";
			break;
		default:
			ans = "Error! Possible data loss. Received unknown command: " 
				+ command + " "+ receivedCommandData;
			receivedCommandData = "";
			break;
		}
		audit("Sent answer: " + String.valueOf(command) + " " + ans);
		return ans;
	}

	public synchronized int getCommand() {
		int tmp = command;
		command = Server.IDLE_COMMAND;
		return tmp;
	}
	
	public void setLogin(String name, String ward){
		Date d = new Date(System.currentTimeMillis());
		audit("Logged in as: " + name + " from: " + ward + " at " + d.toString());
		if (name.equals("Government Agency")){
			isGov = true;
			isDoctor = false;
		} else if (name.split(" ")[0].equals("Doctor")){
			isDoctor = true;
			isGov = false;
		} else {
			isGov = false;
			isDoctor = false;
		}
		loggedInPeer = name;
		loggedInWard = ward;
	}
	
	private void audit(String data){
		try {
			auditFileWriter.write(data);
			auditFileWriter.newLine();
			auditFileWriter.flush();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	
	private void populateWithDocs() {
		documentArchive.put("Benbrott", new Document("Doctor One", "Nurse One", "Avd1", "Patient One"));
		documentArchive.put("Benbrott2", new Document("Doctor Two", "Nurse Two", "Avd2", "Patient Two"));
		documentArchive.put("Armbrott", new Document("Doctor One", "Nurse One", "Avd1", "Patient Two"));
		documentArchive.put("Armbrott2", new Document("Doctor Two", "Nurse Two", "Avd2", "Patient One"));
		documentArchive.put("Skallfraktur", new Document("Doctor One", "Nurse Two", "Avd1", "Patient One"));
		documentArchive.put("Skallfraktur2", new Document("Doctor Two", "Nurse One", "Avd2", "Patient Two"));
		documentArchive.put("Influensa", new Document("Doctor Two", "Nurse One", "Avd1", "Patient One"));
		documentArchive.put("Influensa2", new Document("Doctor One", "Nurse Two", "Avd2", "Patient Two"));
	}

}
